/**
 * 
 */
package org.lightmtv.dispatcher;

import internal.internal.InternalMtvFilter;
import internal.standard.StandardFilterChain;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.lightcommons.logger.LogFactory;
import org.lightcommons.resource.ClassPathResourceLoader;
import org.lightcommons.template.Template;
import org.lightcommons.template.TemplateFactory;
import org.lightcommons.template.commontemplate.CommonTemplateFactory;
import org.lightcommons.web.auth.AuthManager;
import org.lightmtv.LightMtvException;
import org.lightmtv.config.GlobalContext;
import org.lightmtv.config.MtvFilter;
import org.lightmtv.config.MtvFilterChain;
import org.lightmtv.config.Settings;
import org.lightmtv.request.ServletHttpRequest;
import org.lightmtv.response.Response;

/**
 * @author gl
 * @since Jun 30, 2008
 */
public class FilterDispatcher implements Filter{
	
	private TemplateFactory factory;
	private ServletContext servletContext;
	
	public void destroy() {
		
	}

	public void doFilter(ServletRequest req, ServletResponse res,
			FilterChain chain) throws IOException, ServletException {
		try{
			process((HttpServletRequest) req, res, chain);
		}catch(Exception e){
			LightMtvException toThrow=null;
//			if(e instanceof LightMtvTargetException){
//				toThrow = new LightMtvTargetException(e.getCause());
//			}else{
//				toThrow = new LightMtvException(e);
//			}
			if( e instanceof LightMtvException){
				toThrow = (LightMtvException) e;
			}else{
				toThrow = new LightMtvException(e);
			}
			try{
				Map context = new HashMap();
				context.put("req", GlobalContext.getRequest());
				context.put("error", toThrow);
				
				Template template = GlobalContext.getSettings().getTemplateFactory().getTemplate("500.html", "utf-8");
				if(template == null){
					template = factory.getTemplate("500.ctl", "utf-8");
				}
				res.setCharacterEncoding("utf-8");
				template.render(context, res.getWriter());
//				throw toThrow;
				servletContext.log("Error", toThrow);
			}catch(Exception ee){
				throw toThrow;			
			}
		}
	}
	
	private void process(HttpServletRequest req, ServletResponse res,
			FilterChain chain) throws IOException, ServletException{
		ServletHttpRequest request = new ServletHttpRequest(req);
		GlobalContext.setRequest(request);
		AuthManager.setCurrentSession(req.getSession());
		final Settings settings = GlobalContext.getSettings();
		settings.getLifeCycle().beforeRequest(request);
		List<String> filterNames = settings.getFilterPatternMap().getAll(request.getPath());
		List<MtvFilter> filters = new ArrayList<MtvFilter>();
		for(String filterName : filterNames){
			Object filter = settings.getBeanFactory().getBean(filterName);
			filters.add((MtvFilter) filter);
		}
		filters.add(new InternalMtvFilter());
		MtvFilterChain topChain = new StandardFilterChain(filters.iterator());
		Response result = topChain.doFilter(request);
		GlobalContext.getSettings().getLifeCycle().afterResponse(result);
		if(result==null){
			chain.doFilter(req, res);
		}else{
			result.send((HttpServletResponse) res);
		}
	}

	public void init(FilterConfig config) throws ServletException {
		try{
			BootStrap.init(config.getServletContext());
			servletContext = config.getServletContext();
			factory = new CommonTemplateFactory(CommonTemplateFactory.WEB_CONFIG_PATH);
			factory.setResourceLoader(new ClassPathResourceLoader("org/lightmtv/template"));
		}catch(RuntimeException e){
			LogFactory.getLog(getClass()).error("LightMTV init error:",e);
			throw e;
		}
	}
}
